#include "cfbxwidget.h"

#include <cfloat>
#include <cmath>
#include <QFile>
#include <QDir>
#include <QFileInfo>
#include <QMatrix4x4>
#include <QKeyEvent>

FBXViewerWidget::FBXViewerWidget(QWidget *parent)
    : QOpenGLWidget(parent)
    , m_shaderProgram(nullptr)
    , m_timer(nullptr)
    , m_vertexCount(0)
    , m_rotationAngle(0.0f)
    , m_cameraDistance(10.0f)
    , m_rotationX(0.0f)    // 初始化X轴旋转
    , m_rotationY(0.0f)    // 初始化Y轴旋转
    , m_isRotating(false)
{
    setFocusPolicy(Qt::StrongFocus);
    setFocus(); // 立即获取焦点

    // 启用鼠标跟踪
    setMouseTracking(true);
}

FBXViewerWidget::~FBXViewerWidget()
{
    if (m_timer) {
        m_timer->stop();
        delete m_timer;
    }
    if (m_shaderProgram) {
        delete m_shaderProgram;
    }
    cleanupFBXData();
}

void FBXViewerWidget::cleanupFBXData()
{
    for (MeshData* mesh : m_fbxMeshes) {
        if (mesh) {
            mesh->VAO.destroy();
            mesh->VBO.destroy();
            mesh->EBO.destroy();
            delete mesh;
        }
    }
    m_fbxMeshes.clear();
    m_scene.reset();

    // 清理纹理数据
    for (TextureData* texture : m_textures) {
        if (texture && texture->texture) {
            delete texture->texture;
        }
        delete texture;
    }
    m_textures.clear();
}

void FBXViewerWidget::checkGLError(const char* location)
{
    GLenum error = glGetError();
    if (error != GL_NO_ERROR) {
        qDebug() << "OpenGL error at" << location << ":" << error;
    }
}

void FBXViewerWidget::initializeGL()
{
    initializeOpenGLFunctions();

    // 设置清除颜色
    glClearColor(0.1f, 0.1f, 0.4f, 1.0f); // 深蓝色背景

    // 🔍 深度测试设置
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS); // 默认就是GL_LESS，但明确设置一下

    // 🔍 面剔除设置 - 先禁用，确保所有面都渲染
    glDisable(GL_CULL_FACE);
    // glEnable(GL_CULL_FACE);
    // glCullFace(GL_BACK);

    qDebug() << "OpenGL Depth Test: Enabled";
    qDebug() << "OpenGL Face Culling: Disabled";

    setupShaders();

    // 设置定时器
    QTimer* timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &FBXViewerWidget::updateScene);
    timer->start(16);
}

void FBXViewerWidget::wheelEvent(QWheelEvent* event)
{
    // 获取滚轮滚动的角度增量
    QPoint angleDelta = event->angleDelta();

    // 通常我们只关心垂直方向的滚动
    if (!angleDelta.isNull()) {
        // 计算滚轮滚动的距离（可以根据需要调整灵敏度）
        float delta = angleDelta.y() / 120.0f; // 标准滚轮一次滚动通常是120单位

        // 调整相机距离，滚轮向前缩小距离，向后增大距离
        m_cameraDistance = qMax(0.5f, m_cameraDistance - delta * 0.5f);

        qDebug() << "Camera distance:" << m_cameraDistance;

        // 请求重绘
        update();
    }

    // 接受事件，阻止进一步传播
    event->accept();
}

void FBXViewerWidget::keyPressEvent(QKeyEvent* event)
{
    switch (event->key()) {
    case Qt::Key_Up:
        m_cameraDistance -= 0.5f;
        break;
    case Qt::Key_Down:
        m_cameraDistance += 0.5f;
        break;
    case Qt::Key_R:
        m_cameraDistance = 2.0f;
        break;
    }

    update();
}

void FBXViewerWidget::mousePressEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton) {
        m_lastMousePos = event->pos();
        m_isRotating = true;

        // 设置鼠标光标为旋转形状
        setCursor(Qt::ClosedHandCursor);
    }


    // 必须调用accept()来阻止事件传播到父窗口
    event->accept();
}

void FBXViewerWidget::mouseMoveEvent(QMouseEvent* event)
{
    if (m_isRotating && (event->buttons() & Qt::LeftButton)) {
        QPoint currentPos = event->pos();
        QPoint delta = currentPos - m_lastMousePos;

        // 根据鼠标移动更新旋转角度
        // 水平移动控制Y轴旋转（左右看）
        m_rotationY += delta.x() * 0.5f;

        // 垂直移动控制X轴旋转（上下看）
        m_rotationX += delta.y() * 0.5f;

        // 限制X轴旋转角度在 -90° 到 90° 之间，避免过度翻转
        m_rotationX = qBound(-90.0f, m_rotationX, 90.0f);

        // 保持Y轴旋转角度在 0° 到 360° 之间
        if (m_rotationY > 360.0f) m_rotationY -= 360.0f;
        if (m_rotationY < 0.0f) m_rotationY += 360.0f;

        qDebug() << "Rotation - X:" << m_rotationX << "Y:" << m_rotationY;

        m_lastMousePos = currentPos;

        // 请求重绘
        update();
    }

    // 必须调用accept()来阻止事件传播到父窗口
    event->accept();
}

void FBXViewerWidget::mouseReleaseEvent(QMouseEvent* event)
{
    if (event->button() == Qt::LeftButton) {
        m_isRotating = false;

        // 恢复默认鼠标光标
        setCursor(Qt::ArrowCursor);
    }

    // 必须调用accept()来阻止事件传播到父窗口
    event->accept();
}

void FBXViewerWidget::resizeGL(int w, int h)
{
    qDebug() << "resizeGL:" << w << "x" << h;
    glViewport(0, 0, w, h);

    // 更新投影矩阵
    m_projectionMatrix.setToIdentity();
    m_projectionMatrix.perspective(45.0f, float(w) / float(h), 0.1f, 100.0f);

    checkGLError("glViewport");
}

void FBXViewerWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (!m_shaderProgram || !m_shaderProgram->isLinked()) {
        return;
    }

    if (!m_shaderProgram->bind()) {
        return;
    }

    // 更新视图矩阵 - 尝试不同的视角
    m_viewMatrix.setToIdentity();
    m_viewMatrix.translate(0, 0, -m_cameraDistance);

    // 应用鼠标控制的旋转（先Y轴后X轴，这样更自然）
    m_viewMatrix.rotate(m_rotationX, 1.0f, 0.0f, 0.0f);  // X轴旋转（上下看）
    m_viewMatrix.rotate(m_rotationY, 0.0f, 1.0f, 0.0f);  // Y轴旋转（左右看）

    m_viewMatrix.rotate(m_rotationAngle, 0, 1, 0);

    m_shaderProgram->setUniformValue("view", m_viewMatrix);
    m_shaderProgram->setUniformValue("projection", m_projectionMatrix);
    m_shaderProgram->setUniformValue("textureEnabled", true);

    // 渲染FBX模型 - 添加更多调试
    if (!m_fbxMeshes.isEmpty()) {

        for (int i = 0; i < m_fbxMeshes.size(); ++i) {
            MeshData* mesh = m_fbxMeshes[i];
            if (!mesh || !mesh->VAO.isCreated()) continue;

            m_shaderProgram->setUniformValue("color", QVector3D(0.0f, 1.0f, 0.0f)); // 绿色
            m_shaderProgram->setUniformValue("model", QMatrix4x4());

            // 绑定纹理
            if (mesh->textureData && mesh->textureData->texture) {
                mesh->textureData->texture->bind();
                m_shaderProgram->setUniformValue("texture0", 0);
            }

            mesh->VAO.bind();

            // 正常渲染
            glDrawArrays(GL_TRIANGLES, 0, mesh->indexCount);

            mesh->VAO.release();

            // 解绑纹理
            if (mesh->textureData && mesh->textureData->texture) {
                mesh->textureData->texture->release();
            }
        }
    }

    m_shaderProgram->release();
}

void FBXViewerWidget::updateScene()
{
    // 如果没有在手动旋转，才进行自动旋转
    if (!m_isRotating) {
        m_rotationAngle += 0.2f;
        if (m_rotationAngle > 360.0f) {
            m_rotationAngle = 0.0f;
        }
        update();
    }

    update();
}

void FBXViewerWidget::setupShaders()
{
    m_shaderProgram = new QOpenGLShaderProgram(this);

    // 支持纹理的顶点着色器
    const char* vsrc =
        "#version 330 core\n"
        "layout (location = 0) in vec3 aPos;\n"
        "layout (location = 1) in vec3 aNormal;\n"
        "layout (location = 2) in vec2 aTexCoord;\n"
        "uniform mat4 model;\n"
        "uniform mat4 view;\n"
        "uniform mat4 projection;\n"
        "out vec3 FragPos;\n"
        "out vec3 Normal;\n"
        "out vec2 TexCoord;\n"
        "void main()\n"
        "{\n"
        "    FragPos = vec3(model * vec4(aPos, 1.0));\n"
        "    Normal = mat3(transpose(inverse(model))) * aNormal;\n"
        "    TexCoord = aTexCoord;\n"
        "    gl_Position = projection * view * vec4(FragPos, 1.0);\n"
        "}\n";

    // 支持纹理的片段着色器
    const char* fsrc =
        "#version 330 core\n"
        "in vec3 FragPos;\n"
        "in vec3 Normal;\n"
        "in vec2 TexCoord;\n"
        "out vec4 FragColor;\n"
        "uniform bool textureEnabled;\n"
        "uniform sampler2D texture0;\n"
        "void main()\n"
        "{\n"
        "    if (textureEnabled) {\n"
        "        FragColor = texture(texture0, TexCoord);\n"
        "    } else {\n"
        "        // 没有纹理时使用简单的光照\n"
        "        vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));\n"
        "        float diff = max(dot(normalize(Normal), lightDir), 0.3);\n"
        "        FragColor = vec4(0.8 * diff, 0.8 * diff, 0.8 * diff, 1.0);\n"
        "    }\n"
        "}\n";

    if (!m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc)) {
        qDebug() << "Vertex shader error:" << m_shaderProgram->log();
        return;
    }

    if (!m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc)) {
        qDebug() << "Fragment shader error:" << m_shaderProgram->log();
        return;
    }

    if (!m_shaderProgram->link()) {
        qDebug() << "Shader link error:" << m_shaderProgram->log();
        return;
    }
}

bool FBXViewerWidget::loadFBXFile(const QString& filePath)
{
    makeCurrent();
    cleanupFBXData();

    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open file:" << filePath;
        return false;
    }

    QByteArray data = file.readAll();
    file.close();

    // 设置FBX文件所在目录为纹理搜索路径
    QFileInfo fileInfo(filePath);
    m_textureSearchPath = fileInfo.absolutePath();

    // 加载FBX场景
    ofbx::IScene* rawScene = ofbx::load(
        (const ofbx::u8*)data.constData(),
        data.size(),
        static_cast<ofbx::u16>(
            ofbx::LoadFlags::IGNORE_BLEND_SHAPES | ofbx::LoadFlags::IGNORE_SKIN
            )
        );

    if (!rawScene) {
        qDebug() << "Failed to load FBX:" << ofbx::getError();
        return false;
    }

    m_scene.reset(rawScene);

    // 处理FBX场景
    processFBXScene();

    update();
    return true;
}

void FBXViewerWidget::processFBXScene()
{
    if (!m_scene) {
        qDebug() << "No scene to process";
        return;
    }

    int objectCount = m_scene->getAllObjectCount();
    const ofbx::Object* const* allObjects = m_scene->getAllObjects();

    int meshCount = 0;
    for (int i = 0; i < objectCount; ++i) {
        const ofbx::Object* object = allObjects[i];

        if (object && object->getType() == ofbx::Object::Type::MESH) {
            processMesh(static_cast<const ofbx::Mesh*>(object), QMatrix4x4());
            meshCount++;
        }
    }
}

void FBXViewerWidget::processMesh(const ofbx::Mesh* mesh, const QMatrix4x4& parentTransform)
{
    if (!mesh) {
        qDebug() << "Mesh is null";
        return;
    }

    const ofbx::Geometry* geometry = mesh->getGeometry();
    if (!geometry) {
        qDebug() << "No geometry in mesh";
        return;
    }

    const auto& geomData = geometry->getGeometryData();
    if (!geomData.hasVertices()) {
        qDebug() << "Mesh has no vertices";
        return;
    }

    // 获取顶点数据
    auto positions = geomData.getPositions();
    auto normals = geomData.getNormals();
    auto uvs = geomData.getUVs(0);

    if (positions.count == 0) {
        qDebug() << "No position data";
        return;
    }

    // 收集顶点和索引数据
    QVector<Vertex> vertices;
    QVector<unsigned int> indices;

    // 处理所有几何分区
    int partitionCount = geomData.getPartitionCount();
    qDebug() << "Partition count:" << partitionCount;

    int totalTriangles = 0;
    int invalidIndexCount = 0;

    for (int p = 0; p < partitionCount; ++p) {
        auto partition = geomData.getPartition(p);
        qDebug() << "Partition" << p << "polygon_count:" << partition.polygon_count;

        for (int polyIdx = 0; polyIdx < partition.polygon_count; ++polyIdx) {
            auto polygon = partition.polygons[polyIdx];
            qDebug() << "Polygon" << polyIdx << "vertex_count:" << polygon.vertex_count;

            // 三角化多边形
            QVector<int> triIndices(polygon.vertex_count * 3);
            int triCount = ofbx::triangulate(geomData, polygon, triIndices.data());
            qDebug() << "Triangulated to" << triCount << "triangles";

            if (triCount <= 0) {
                qDebug() << "Triangulation failed for polygon" << polyIdx;
                continue;
            }

            for (int i = 0; i < triCount; ++i) {
                int vertexIndex = triIndices[i];

                // 🔍 检查顶点索引是否有效
                if (vertexIndex < 0 || vertexIndex >= positions.count) {
                    qDebug() << "Warning: Invalid vertex index:" << vertexIndex << "max:" << positions.count << "using 0 instead";
                    vertexIndex = 0; // 使用安全值
                    invalidIndexCount++;
                }

                Vertex vertex;
                vertex.position = toQVector(positions.get(vertexIndex));

                // 🔍 检查顶点数据有效性
                if (std::isnan(vertex.position.x()) || std::isnan(vertex.position.y()) || std::isnan(vertex.position.z())) {
                    qDebug() << "Warning: Invalid vertex position at index" << vertexIndex << "using zero vector";
                    vertex.position = QVector3D(0, 0, 0);
                }

                if (normals.count > 0 && vertexIndex < normals.count) {
                    vertex.normal = toQVector(normals.get(vertexIndex));
                    if (std::isnan(vertex.normal.x()) || std::isnan(vertex.normal.y()) || std::isnan(vertex.normal.z())) {
                        vertex.normal = QVector3D(0, 1, 0);
                    }
                } else {
                    vertex.normal = QVector3D(0, 1, 0); // 默认法线
                }

                if (uvs.count > 0 && vertexIndex < uvs.count) {
                    vertex.texCoord = toQVector(uvs.get(vertexIndex));
                    if (std::isnan(vertex.texCoord.x()) || std::isnan(vertex.texCoord.y())) {
                        vertex.texCoord = QVector2D(0, 0);
                    }
                } else {
                    vertex.texCoord = QVector2D(0, 0); // 默认UV
                }

                vertices.append(vertex);
                indices.append(vertices.size() - 1);
            }
            totalTriangles += triCount;
        }
    }

    if (vertices.isEmpty() || indices.isEmpty()) {
        qDebug() << "No vertex or index data after processing";
        return;
    }

    QVector3D minBound(FLT_MAX, FLT_MAX, FLT_MAX);
    QVector3D maxBound(-FLT_MAX, -FLT_MAX, -FLT_MAX);

    for (const Vertex& vertex : vertices) {
        minBound.setX(qMin(minBound.x(), vertex.position.x()));
        minBound.setY(qMin(minBound.y(), vertex.position.y()));
        minBound.setZ(qMin(minBound.z(), vertex.position.z()));
        maxBound.setX(qMax(maxBound.x(), vertex.position.x()));
        maxBound.setY(qMax(maxBound.y(), vertex.position.y()));
        maxBound.setZ(qMax(maxBound.z(), vertex.position.z()));
    }

    QVector3D center = (minBound + maxBound) * 0.5f;
    QVector3D size = maxBound - minBound;
    float maxSize = qMax(size.x(), qMax(size.y(), size.z()));

    // 创建MeshData
    MeshData* meshData = new MeshData();

    // 🔍 关键修改：添加适当的缩放和位移
    QMatrix4x4 transform = toQMatrix(mesh->getLocalTransform());

    // 如果模型太小，自动缩放
    float scaleFactor = 1.0f;
    if (maxSize > 0.0f && maxSize < 1.0f) {
        scaleFactor = 1.0f / maxSize;
    } else if (maxSize > 10.0f) {
        scaleFactor = 10.0f / maxSize;
    }

    // 应用缩放和位移
    transform.scale(scaleFactor);
    transform.translate(-center * scaleFactor); // 居中

    meshData->transform = transform;

    // 加载纹理
    if (mesh->getMaterialCount() > 0) {
        const ofbx::Material* material = mesh->getMaterial(0);
        if (material) {
            const ofbx::Texture* diffuseTexture = material->getTexture(ofbx::Texture::DIFFUSE);
            if (diffuseTexture) {
                meshData->textureData = loadTexture(diffuseTexture);
                if (meshData->textureData) {
                    qDebug() << "Loaded texture for mesh:" << meshData->textureData->filePath;
                }
            }
            else
            {
                meshData->textureData = loadTextureFromFile();
                if (meshData->textureData) {
                    qDebug() << "Loaded texture for mesh:" << meshData->textureData->filePath;
                }
            }
        }
    }

    // 如果没有纹理，创建默认纹理
    if (!meshData->textureData) {
        meshData->textureData = createDefaultTexture();
        qDebug() << "Using default texture for mesh";
    }

    // 创建VAO和VBO
    if (!meshData->VAO.create()) {
        qDebug() << "Failed to create VAO";
        delete meshData;
        return;
    }
    meshData->VAO.bind();

    if (!meshData->VBO.create()) {
        qDebug() << "Failed to create VBO";
        delete meshData;
        return;
    }
    meshData->VBO.bind();
    meshData->VBO.setUsagePattern(QOpenGLBuffer::StaticDraw);

    // 展开顶点数据
    QVector<Vertex> expandedVertices;
    for (int i = 0; i < indices.size(); ++i) {
        expandedVertices.append(vertices[indices[i]]);
    }

    // 上传展开后的顶点数据
    meshData->VBO.allocate(expandedVertices.constData(), expandedVertices.size() * sizeof(Vertex));
    meshData->indexCount = expandedVertices.size();

    // 设置顶点属性
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texCoord));

    // 检查顶点属性设置
    for (int attr = 0; attr < 3; ++attr) {
        GLint enabled;
        glGetVertexAttribiv(attr, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
        qDebug() << "Vertex attribute" << attr << "enabled after setup:" << enabled;
    }

    meshData->VAO.release();
    meshData->VBO.release();

    m_fbxMeshes.append(meshData);
}

TextureData* FBXViewerWidget::loadTextureFromFile(void)
{
    if(m_defaulttexturepath == "") return nullptr;

    // 尝试在FBX文件所在目录查找纹理
    QImage image;
    if (QFile::exists(m_defaulttexturepath)) {
        image.load(m_defaulttexturepath);
        qDebug() << "Texture found at:" << m_defaulttexturepath;
    } else if (QFile::exists(m_defaulttexturepath)) {
        image.load(m_defaulttexturepath);
        qDebug() << "Texture found at:" << m_defaulttexturepath;
    } else {
        qDebug() << "Texture not found, searching in FBX directory...";
        // 在FBX目录中搜索任何图片文件
        QDir textureDir(m_textureSearchPath);
        QStringList imageFilters = {"*.png", "*.jpg", "*.jpeg", "*.bmp", "*.tga"};
        QStringList imageFiles = textureDir.entryList(imageFilters, QDir::Files);

        if (!imageFiles.isEmpty()) {
            image.load(m_textureSearchPath);
            qDebug() << "Using found texture:" << m_defaulttexturepath;
        } else {
            qDebug() << "No texture files found in FBX directory";
            return nullptr;
        }
    }

    if (image.isNull()) {
        qDebug() << "Failed to load texture image";
        return nullptr;
    }

    // 创建纹理数据
    TextureData* textureData = new TextureData();
    textureData->filePath = m_defaulttexturepath;
    textureData->texture = new QOpenGLTexture(image.mirrored());
    textureData->texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    textureData->texture->setMagnificationFilter(QOpenGLTexture::Linear);
    textureData->texture->setWrapMode(QOpenGLTexture::Repeat);

    m_textures.append(textureData);
    return textureData;
}

TextureData* FBXViewerWidget::loadTexture(const ofbx::Texture* fbxTexture)
{
    if (!fbxTexture) return nullptr;

    // 获取纹理文件名
    char filename[256];
    fbxTexture->getRelativeFileName().toString(filename);
    QString texturePath = QString::fromUtf8(filename);

    qDebug() << "Trying to load texture:" << texturePath;

    // 尝试在FBX文件所在目录查找纹理
    QString fullPath = m_textureSearchPath + "/" + QFileInfo(texturePath).fileName();

    QImage image;
    if (QFile::exists(fullPath)) {
        image.load(fullPath);
        qDebug() << "Texture found at:" << fullPath;
    } else if (QFile::exists(texturePath)) {
        image.load(texturePath);
        qDebug() << "Texture found at:" << texturePath;
    } else {
        qDebug() << "Texture not found, searching in FBX directory...";
        // 在FBX目录中搜索任何图片文件
        QDir textureDir(m_textureSearchPath);
        QStringList imageFilters = {"*.png", "*.jpg", "*.jpeg", "*.bmp", "*.tga"};
        QStringList imageFiles = textureDir.entryList(imageFilters, QDir::Files);

        if (!imageFiles.isEmpty()) {
            fullPath = m_textureSearchPath + "/" + imageFiles.first();
            image.load(fullPath);
            qDebug() << "Using found texture:" << fullPath;
        } else {
            qDebug() << "No texture files found in FBX directory";
            return nullptr;
        }
    }

    if (image.isNull()) {
        qDebug() << "Failed to load texture image";
        return nullptr;
    }

    // 创建纹理数据
    TextureData* textureData = new TextureData();
    textureData->filePath = fullPath;
    textureData->texture = new QOpenGLTexture(image.mirrored());
    textureData->texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    textureData->texture->setMagnificationFilter(QOpenGLTexture::Linear);
    textureData->texture->setWrapMode(QOpenGLTexture::Repeat);

    m_textures.append(textureData);
    return textureData;
}

TextureData* FBXViewerWidget::createDefaultTexture()
{
    // 创建128x128的默认棋盘格纹理
    QImage image(128, 128, QImage::Format_RGB32);

    for (int y = 0; y < image.height(); ++y) {
        for (int x = 0; x < image.width(); ++x) {
            bool isDark = ((x / 16) % 2) ^ ((y / 16) % 2);
            QRgb color = isDark ? qRgb(100, 100, 100) : qRgb(200, 200, 200);
            image.setPixel(x, y, color);
        }
    }

    TextureData* textureData = new TextureData();
    textureData->filePath = "default_checkerboard";
    textureData->texture = new QOpenGLTexture(image);
    textureData->texture->setMinificationFilter(QOpenGLTexture::Linear);
    textureData->texture->setMagnificationFilter(QOpenGLTexture::Linear);
    textureData->texture->setWrapMode(QOpenGLTexture::Repeat);

    m_textures.append(textureData);
    return textureData;
}

QMatrix4x4 FBXViewerWidget::toQMatrix(const ofbx::DMatrix& fbxMatrix)
{
    QMatrix4x4 matrix;
    for (int i = 0; i < 16; ++i) {
        matrix.data()[i] = float(fbxMatrix.m[i]);
    }
    return matrix;
}

QVector3D FBXViewerWidget::toQVector(const ofbx::DVec3& vec)
{
    return QVector3D(float(vec.x), float(vec.y), float(vec.z));
}

QVector2D FBXViewerWidget::toQVector(const ofbx::Vec2& vec)
{
    return QVector2D(vec.x, vec.y);
}

QVector3D FBXViewerWidget::toQVector(const ofbx::Vec3& vec)
{
    return QVector3D(vec.x, vec.y, vec.z);
}
